package com.linkoog.devtools.type;

import com.intellij.psi.PsiArrayType;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiModifierList;
import com.intellij.psi.PsiPrimitiveType;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeParameter;
import com.intellij.psi.PsiWildcardType;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.util.PsiUtil;
import com.linkoog.devtools.type.javadoc.JavaDoc;
import com.linkoog.devtools.type.javadoc.JavaDocParser;
import com.linkoog.devtools.type.swagger.JavaSwaggerParser;
import com.linkoog.devtools.type.swagger.SwaggerFieldDoc;
import com.linkoog.devtools.type.impl.ArrayType;
import com.linkoog.devtools.type.impl.FileType;
import com.linkoog.devtools.type.impl.IgnoreType;
import com.linkoog.devtools.type.impl.LiteralTypes;
import com.linkoog.devtools.type.impl.MapType;
import com.linkoog.devtools.type.impl.ObjectFieldDoc;
import com.linkoog.devtools.type.impl.ObjectType;
import com.linkoog.devtools.type.impl.UnknownType;
import com.linkoog.devtools.type.impl.WildcardType;
import com.linkoog.devtools.utils.StringUtils;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class TypeParser {


    public static Type parse(PsiType psiType){
        try {
            Map<String,ObjectType> parentTypes = new HashMap<>();
            return parsePsiType(psiType, parentTypes);
        }catch (Exception e){
            return new ObjectType(psiType.getCanonicalText(), psiType.getPresentableText(), psiType.getPresentableText(), psiType.getPresentableText());
        }
    }

    /**
     */
    protected static Type parsePsiType(PsiType psiType, Map<String,ObjectType> parentTypes){
        if (psiType == null){
            return null;
        }

        //当前类型，是否在父级中存在，避免树形结构和循环引用结构的内存溢出问题
        if (parentTypes.containsKey(psiType.getCanonicalText())){
            ObjectType objectType =  parentTypes.get(psiType.getCanonicalText());
            return objectType.clone();
        }

        // 不解析的内置类型
        final IgnoreType ignoreType = TypeParserUtils.ignoreTypeParser(psiType.getCanonicalText());
        if (ignoreType != null) return ignoreType;

        if ("void".equals(psiType.getCanonicalText())){
            return LiteralTypes.VoidLiteralType;
        } else if (psiType instanceof PsiPrimitiveType psiPrimitiveType){
            //基本数据类型
            return LiteralTypes.valueByFullName(psiPrimitiveType.getName());
        } else if (psiType instanceof PsiArrayType psiArrayType){
            //数组类型
            PsiType componentType = psiArrayType.getComponentType();

            Type dataType = parsePsiType(componentType, parentTypes);
            return new ArrayType(dataType);
        } else if (psiType instanceof PsiClassReferenceType psiClassReferenceType){

            PsiClass psiClass =  psiClassReferenceType.resolve();
            //会出现null场景:
            // 1、未设置jdk
            // 2、文件不在 source 目录
            if (psiClass == null) return null;

            //当前类,为简单的数据类型:
            // 基础类型和封装类型
            LiteralType literalType = LiteralTypes.valueByFullName(psiClass.getQualifiedName());
            if (literalType != null) return literalType;

            //1.number类型  2.string类型   3.date类型
            LiteralType derivativeLiteralType = TypeParserUtils.parseDerivativeLiteralType(psiClass);
            if (derivativeLiteralType != null) return derivativeLiteralType;

            //文件类型
            if (TypeParserUtils.isFileType(psiClass)){
                //psiType.getCanonicalText()  psiType.getPresentableText()
                return new FileType(psiType.getPresentableText(), psiClass.getQualifiedName());
            }



            /*---------------------------对象类型解析-----------------------------------------------------*/

            //当前字段的实际泛型
            PsiType[] fieldWildcardParamPsiTypes = psiClassReferenceType.getParameters();
            boolean hasWildcardParam = fieldWildcardParamPsiTypes.length != 0; //是否有实际的泛型参数

            //当前类, 为list类型
            if (TypeParserUtils.isCollectionType(psiClass)){
                Type dataType;
                if (hasWildcardParam){
                    dataType = parsePsiType(fieldWildcardParamPsiTypes[0], parentTypes);
                } else {
                    dataType = new ObjectType("Object", "java.lang.Object", "Object","java.lang.Object");
                }

                //psiType.getPresentableText()  psiClass.getQualifiedName() psiType.getCanonicalText()
                return new ArrayType(psiType.getPresentableText(), psiClass.getQualifiedName(), dataType);
            }

            //当前类, 为map类型
            if (TypeParserUtils.isMapType(psiClass)){
                Type keyType, valType;
                if (hasWildcardParam){
                    keyType = parsePsiType(fieldWildcardParamPsiTypes[0], parentTypes);
                    valType = parsePsiType(fieldWildcardParamPsiTypes[1], parentTypes);
                } else {
                    keyType = new ObjectType("Object", "java.lang.Object", "Object","java.lang.Object");
                    valType = new ObjectType("Object", "java.lang.Object", "Object","java.lang.Object");
                }

                return new MapType(keyType, valType);
            }

            //当前类, 为无泛型或带泛型的pojo实体类
            ObjectType objectType = new ObjectType(psiType.getCanonicalText(), psiClass.getQualifiedName(), psiClass.getQualifiedName(), psiType.getPresentableText());
            //当前类,为pojo实体类时，添加到set中，为下级字段是否为父类的判断，做数据准备
            parentTypes.put(psiClass.getQualifiedName(), objectType);


            Map<String, PsiType> wildcardFieldMetaDataMap = new HashMap<>();
            Iterator<PsiTypeParameter> typeParameterIterator = PsiUtil.typeParametersIterator(psiClass); //遍历类的泛型声明
            for (int i= 0; typeParameterIterator.hasNext() ; i ++){
                PsiTypeParameter psiTypeParameter = typeParameterIterator.next();
                if (i < fieldWildcardParamPsiTypes.length){
                    //当字段上设置了泛型时
                    PsiType wildcardPsiType = fieldWildcardParamPsiTypes[i];
                    wildcardFieldMetaDataMap.put(psiTypeParameter.getName(), wildcardPsiType);
                } else {
                    wildcardFieldMetaDataMap.put(psiTypeParameter.getName(), null);
                }
            }

            //当前类，解析所有字段
            Map<String, Type> fieldTypeMap = new HashMap<>();
            Map<String, ObjectFieldDoc> fieldDocMap = new HashMap<>();
            for (PsiField psiField : psiClass.getAllFields()) {
                //去除静态属性  modifierList.hasModifierProperty(PsiModifier.FINAL)
                final PsiModifierList modifierList = psiField.getModifierList();
                if (modifierList != null && modifierList.hasModifierProperty(PsiModifier.STATIC)) {
                    continue;
                }

                Type fieldType = null;
                if (wildcardFieldMetaDataMap.containsKey(psiField.getType().getCanonicalText())){
                    //处理泛型字段，wildcardPsiType 为泛型的实际类型
                    PsiType wildcardPsiType = wildcardFieldMetaDataMap.get(psiField.getType().getCanonicalText());
                    if (wildcardPsiType == null){
                        //字段为泛型，但是无实际泛型
                        fieldType = new UnknownType();
                    }else {
                        fieldType = parsePsiType(wildcardPsiType, parentTypes);
                    }
                } else {
                    //不是泛型的字段
                    fieldType = parsePsiType(psiField.getType(), parentTypes);
                }

                ObjectFieldDoc objectFieldDoc = new ObjectFieldDoc();
                objectFieldDoc.setName(psiField.getName());

                //java 字段文档解析
                JavaDoc javaDoc = JavaDocParser.parse(psiField.getDocComment());
                if (javaDoc != null){
                    objectFieldDoc.setDescription(javaDoc.getDescription());
                }

                //swagger文档解析
                SwaggerFieldDoc swaggerFieldDoc = JavaSwaggerParser.parseField(psiField);
                if (swaggerFieldDoc != null){
                    objectFieldDoc.setRequired(swaggerFieldDoc.isRequired());
                    objectFieldDoc.setExample(swaggerFieldDoc.getExample());
                    if (StringUtils.isNotBlank(swaggerFieldDoc.getValue())){
                        objectFieldDoc.setDescription(swaggerFieldDoc.getValue());
                    }
                }

                //验证注解
                objectFieldDoc.setRequired(TypeParserUtils.hasValidationAnno(psiField));

                fieldTypeMap.put(psiField.getName(), fieldType);
                fieldDocMap.put(psiField.getName(), objectFieldDoc);
            }

            objectType.setFieldTypeMap(fieldTypeMap);
            objectType.setFieldDocMap(fieldDocMap);

            //当前类,是否有泛型声明
            /*boolean hasTypeWildcard = !wildcardFieldMetaDataMap.isEmpty();
            if (hasTypeWildcard){

            }*/


            return objectType;
        } else if (psiType instanceof PsiWildcardType psiWildcardType){
            //泛型类型：？*

            WildcardType wildcardType = new WildcardType(psiWildcardType.getPresentableText(), psiWildcardType.getCanonicalText());
            return wildcardType;
        }

        return null;
    }





}
